/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bef.engine.entity;

import com.inspur.edp.bef.api.BefRtBeanUtil;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.LogicDeleteControlInfo;
import com.inspur.edp.bef.engine.entity.exception.BefEngineExceptionBase;
import com.inspur.edp.bef.engine.entity.exception.ErrorCodes;
import com.inspur.edp.bef.engine.entity.propertyinfobuilder.BefPropInfoGenerator;
import com.inspur.edp.bef.engine.util.DataTypeConvertor;
import com.inspur.edp.bef.spi.entity.CodeRuleInfo;
import com.inspur.edp.bef.spi.entity.builtinimpls.BefEntityResInfoImpl;
import com.inspur.edp.bef.spi.entity.columnconfig.ColumnGenerateInfo;
import com.inspur.edp.cef.api.repository.GspDbDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationKeyCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociationKey;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.spi.entity.LogicDeleteResInfo;
import com.inspur.edp.cef.spi.entity.info.UniqueConstraintInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefModelResInfoImpl;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.entity.element.GspBillCodeGenerateOccasion;
import com.inspur.edp.das.commonmodel.entity.object.GspUniqueConstraint;
import io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectColumn;
import io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectTableCore;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

public class EntityResourceInfo extends BefEntityResInfoImpl {
    private final GspBizEntityObject obj;
    private final BeModelResInfo beModelResInfo;
    private final GspBusinessEntity businessEntity;

    private String primaryKey;
    private String parentKey;

    public EntityResourceInfo(GspBizEntityObject obj, BeModelResInfo beModelResInfo,
                              GspBusinessEntity businessEntity) {
        super(obj.getCode(), obj.getI18nResourceInfoPrefix() + ".Name", beModelResInfo, obj.getID(), obj.getName());
        this.beModelResInfo = beModelResInfo;
        this.businessEntity = businessEntity;
        this.obj = obj;
        initColumns1();
        initUQConstraintInfos1();
        initChildInfos1(beModelResInfo);
        if (isRoot() && businessEntity.getVersionContronInfo() != null
                && StringUtils.isNotEmpty(businessEntity.getVersionContronInfo().getVersionControlElementId())) {
            setVersionControlPropertyName(
                    obj.findElement(businessEntity.getVersionContronInfo().getVersionControlElementId()).getLabelID());
        }
        intCodeRuleInfos();
        initColumnGenerateInfo();
    }

    private void intCodeRuleInfos() {
        for (IGspCommonField item : obj.getContainElements()) {
            IGspCommonElement element = (IGspCommonElement) item;

            if (!element.getBillCodeConfig().getCanBillCode()) {
                continue;
            }

            if (element.getBillCodeConfig().getCodeGenerateOccasion() == GspBillCodeGenerateOccasion.SavingTime) {
                addBeforeSaveCodeRuleInfo(element);
            } else if (element.getBillCodeConfig().getCodeGenerateOccasion() == GspBillCodeGenerateOccasion.CreatingTime) {
                addAfterCreateCodeRuleInfo(element);
            }
        }
    }

    private void initColumnGenerateInfo() {
        ColumnGenerateInfo info = new ColumnGenerateInfo();
        info.setGenerateType(obj.getColumnGenerateID().getGenerateType());
        if (obj.getColumnGenerateID().getCloumnParameter() != null && !obj.getColumnGenerateID().getCloumnParameter().isEmpty()) {
            info.getParams().addAll(obj.getColumnGenerateID().getCloumnParameter());
        }
        this.setColumnGenerateInfo(info);
    }

    private void addBeforeSaveCodeRuleInfo(IGspCommonElement element) {
        CodeRuleInfo codeRuleInfo = new CodeRuleInfo();
        codeRuleInfo.setCodeRuleId(element.getBillCodeConfig().getBillCodeID());
        getBeforeSaveCodeRules().put(element.getLabelID(), codeRuleInfo);
    }

    private void addAfterCreateCodeRuleInfo(IGspCommonElement element) {
        CodeRuleInfo codeRuleInfo = new CodeRuleInfo();
        codeRuleInfo.setCodeRuleId(element.getBillCodeConfig().getBillCodeID());
        getAfterCreateCodeRules().put(element.getLabelID(), codeRuleInfo);
    }

    @Override
    protected void initColumns() {
        super.initColumns();
    }

    /**
     * 返回主键LabelID信息
     * @return 主键LabelID
     */
    public String getPrimaryKey() {
        if(StringUtils.isEmpty(this.primaryKey)){
            //根据ID信息构造主键，对应LabelID
            List<String> keys = obj.getPrimaryKeys();
            this.primaryKey = String.join(",", keys);
        }
        return this.primaryKey;
    }

    public String getParentProprety() {
        if(obj.getIsRootNode()) {
            return null;
        }
        if(StringUtils.isEmpty(this.parentKey)) {
            //根据外键集合构造
            GspAssociationKeyCollection collection = obj.getKeys();
            List<String> parentKeys = new ArrayList<>();
            for(GspAssociationKey key : collection){
                String sourceElementId = key.getSourceElement();
                IGspCommonElement element = obj.findElement(sourceElementId);
                if(element!=null) {
                    parentKeys.add(element.getLabelID());
                }
            }
            this.parentKey = String.join(",", parentKeys);
        }
        return this.parentKey;
    }

    protected void initColumns1() {
        //todo 好多地方都重复了，BefBaseAdaptor的columns也用dbo进行构造
        DatabaseObjectTableCore dbo = (DatabaseObjectTableCore) BefRtBeanUtil.getDboRtService().getDatabaseObject(obj.getRefObjectName());
        if (dbo == null) {
            throw new BefEngineExceptionBase(ErrorCodes.BEF_ENGINE_0013, obj.getBelongModel().getName(),
                    obj.getName(), obj.getRefObjectName());

        }
        for (IGspCommonField field : obj.getContainElements()) {
            if (field.getObjectType() == GspElementObjectType.Association && (field.getChildAssociations() == null
                    || field.getChildAssociations().isEmpty())) {
                continue;
            }
            DataTypePropertyInfo dataTypePropertyInfo = new BefPropInfoGenerator().getDataTypePropertyInfo(field);
            //是为了长度校验时，识别出smallInt类型字段进行值范围比较，给dataTypePropertyInfo增加数据类型字段
            DatabaseObjectColumn column = dbo.getColumnById(((IGspCommonElement) field).getColumnID());
            if(column != null){
                GspDbDataType gspDbDataType = DataTypeConvertor.transDataType(column.getDataType());
                dataTypePropertyInfo.setDbDataType(gspDbDataType);
            }

            addPropertyInfo(dataTypePropertyInfo);
        }
    }

    protected void initUQConstraintInfos1() {
        if (obj.getContainConstraints() == null || obj.getContainConstraints().isEmpty())
            return;
        for (GspUniqueConstraint gspUniqueConstraint : obj.getContainConstraints()) {
            UniqueConstraintInfo uniqueConstraintInfo = new UniqueConstraintInfo();
            uniqueConstraintInfo.setDisplayValueKey(gspUniqueConstraint.getI18nResourceInfoPrefix() + ".TipInfo");
            ArrayList<String> elements = new ArrayList<>();
            for (String eleID : gspUniqueConstraint.getElementList()) {
                elements.add(obj.findElement(eleID).getLabelID());
            }
            uniqueConstraintInfo.setFields(elements);
            uniqueConstraintInfo.setNodeCode(obj.getCode());
            // 默认显示名称
            uniqueConstraintInfo.setDefaultDisplayName(gspUniqueConstraint.getName());
            addUQConstraintInfo(gspUniqueConstraint.getCode(), uniqueConstraintInfo);
        }
    }

    @Override
    public boolean isRoot() {
        return obj.getIsRootNode();
    }

    @Override
    public String getConfigId() {
        return businessEntity.getDotnetGeneratedConfigID();
    }

    protected void initChildInfos1(CefModelResInfoImpl modelResInfo) {
        if (obj.getContainChildObjects() == null || obj.getContainChildObjects().isEmpty()) {
            return;
        }
        for (IGspCommonObject childObj : obj.getContainChildObjects()) {
            addChildEntityResInfo(new EntityResourceInfo((GspBizEntityObject) childObj, beModelResInfo, businessEntity));
        }
    }

    public LogicDeleteResInfo getLogicDeleteResInfo() {
        LogicDeleteControlInfo logicDeleteControlInfo = this.obj.getLogicDeleteControlInfo();
        if (logicDeleteControlInfo == null)
            return null;
        return new LogicDeleteResInfo(logicDeleteControlInfo.getEnableLogicDelete(), logicDeleteControlInfo.getLogicDeleteControlElementId());
    }

    protected GspBizEntityObject getBizEntityObject() {
        return this.obj;
    }

    protected BeModelResInfo getBeModelResInfo() {
        return this.beModelResInfo;
    }

    protected GspBusinessEntity getBusinessEntity() {
        return this.businessEntity;
    }
}
